-
Notifications
You must be signed in to change notification settings - Fork 358
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: manage Notifier storage usage [DHIS2-17998] #19738
Conversation
...pport/dhis-support-system/src/main/java/org/hisp/dhis/system/notification/NotifierStore.java
Fixed
Show fixed
Hide fixed
} | ||
|
||
@Test | ||
void testInsertingNotificationJobConcurrently() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI: This test is no longer possible without waiting a minute so I removed it.
@@ -192,6 +192,9 @@ public boolean isDefaultExecutedByCreator() { | |||
} | |||
|
|||
/** | |||
* @implNote since 2.42 all jobs forward to the {@link org.eclipse.emf.common.notify.Notifier} but |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should this be the DHIS Notifier?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
woops
* | ||
* @author Jan Bernitt | ||
*/ | ||
record FakeRedis( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was using a Redis test container looked into? Any specific reasons why this would be preferable over something that would more closely mirror actual use?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, I did not. I wanted something that can be used in unit tests so the tests run fast and don't add in another level of complexity.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like a very good & useful improvement 👍
Quality Gate passedIssues Measures |
* feat: gist for overview lists, limit setting [DHIS2-17998] * refactor: NotifierStore implemented * feat: clear and cap API and endpoints * feat: cap for redis store * fix: cap and clean consistency, log level filter for scheduling only * chore: API cleanup, javadoc, some test fixes * fix: notifier tests * fix: hide transient empty in-memory stores in the API * fix: update test assert with new message * fix: remove notifier stubbing from mock test * fix: e2e test assert for updated message * fix: mock test setup, dependencies * fix: add jackson core back in * fix: exclude jackson core from dependency check * fix: sonar issues * test: notifier API tests for in-memory and redis * fix: sonar warnings * chore: fix typo
* feat: manage Notifier storage usage [DHIS2-17998] (#19738) * feat: gist for overview lists, limit setting [DHIS2-17998] * refactor: NotifierStore implemented * feat: clear and cap API and endpoints * feat: cap for redis store * fix: cap and clean consistency, log level filter for scheduling only * chore: API cleanup, javadoc, some test fixes * fix: notifier tests * fix: hide transient empty in-memory stores in the API * fix: update test assert with new message * fix: remove notifier stubbing from mock test * fix: e2e test assert for updated message * fix: mock test setup, dependencies * fix: add jackson core back in * fix: exclude jackson core from dependency check * fix: sonar issues * test: notifier API tests for in-memory and redis * fix: sonar warnings * chore: fix typo * chore: prevent null message logging + log cleanup [DHIS2-17998] (#19800) * fix: maven dependencies + mock tests * fix: add Long conversion * fix: e2e test message expectations after change in wording
* feat: manage Notifier storage usage [DHIS2-17998] (#19738) * feat: gist for overview lists, limit setting [DHIS2-17998] * refactor: NotifierStore implemented * feat: clear and cap API and endpoints * feat: cap for redis store * fix: cap and clean consistency, log level filter for scheduling only * chore: API cleanup, javadoc, some test fixes * fix: notifier tests * fix: hide transient empty in-memory stores in the API * fix: update test assert with new message * fix: remove notifier stubbing from mock test * fix: e2e test assert for updated message * fix: mock test setup, dependencies * fix: add jackson core back in * fix: exclude jackson core from dependency check * fix: sonar issues * test: notifier API tests for in-memory and redis * fix: sonar warnings * chore: fix typo * chore: prevent null message logging + log cleanup [DHIS2-17998] (#19800) * fix: maven dependencies + mock tests * fix: add Long conversion * fix: e2e test message expectations after change in wording
Summary
PR improves the automatic and manual management of the amount of storage allocated by the
Notifier
(/api/system/tasks
and/api/system/taskSummaries
) API. In that context multiple new system settings were introduced to tune the automatic caps and cleanup behavior.New System Settings
notifierLogLevel
: what level of messages to include in the log/list, defaultDEBUG
(all)notifierMaxMessagesPerJob
: each job can at most have this amount of messages in its list (soft enforced allowing momentary exceeding the limit by a few); default is500
notifierMaxAgeDays
: job data older than this number of days is discarded (soft enforced, cleanup after 1 minute of idle); default is7
notifierMaxJobsPerType
: if perJobType
there are more than this number of jobs with data the oldest are discarded to get below this limit (soft enforced, cleanup after 1 minute idle); default is500
notifierGistOverview
: whentrue
the overview pages will only show the first and last message of the list for each job; defaulttrue
notifierCleanAfterIdleTime
: the time in milliseconds the notifier has to be idle (not moving messages from queue to store) before an automatic store cleanup is run using thenotifierMaxAgeDays
andnotifierMaxJobsPerType
as caps; default is60
secNew API Endpoints
DELETE /api/system/tasks
: delete all data (of all jobs of any type)DELETE /api/system/tasks/{job-type}
: delete all data of of all jobs of that typeDELETE /api/system/tasks/{job-type}/{job-id}
: delete all data of the jobWhen not just deleting data for a specific job (first 2 URLs) 2 optional parameters can be used:
maxAge
: limits the deletion to jobs that are at least of that age in days, e.g.maxAge=5
to delete all job data for jobs older than 5 daysmaxCount
: limit the deletion so at most data for this number of jobs is kept, oldest jobs are deleted; e.g.maxCount=10
to keep data for the 10 jobs which have the most recent data"All data" always means both notifications and summary. Therefore there is no equivalent deletion with
/api/taskSummaries
.Asynchronous Notifications
The new implementation of the
Notifier
uses aBlockingQueue
to decouple the sources ofNotification
messages from the storage part. This has several advantages, but mainly was needed to know that adding messages to the store is never concurrent to other writes or cleanup. That simplifies a lot how the operations can be implemented. As a bonus it should also improve performance of jobs slightly. In addition exceptions from notification and storage will never escalate to the job thread.The single thread processing also allowed to make sure all messages will always have an increase of at least 1ms
in their timestamp and that all message timestamps reflect the actual store insert order. Timestamps are only adjusted when needed.
Storage Changes
Notification
itself got reduced since it contained multiple fields that can be recovered from contextJsonValue
- it is never converted back to its object model (just to be turned into JSON again in the API layer) which has less overhead and less issues with changes, class renames, moves etcetera.notifications:
key namespace is used to store the list of notifications (age of collection is extracted from most recent message)summaries:
key namespace is used to store the summary as JSON (to remember the time the value is wrapped and unwrapped in another object, but the code can detect and handle existing values without the wrapper)NotifierStore
layer was introduced which handles the difference between in-memory and redis. TheNotifier
implementation itself is now common code. This allowed to keep each of the operations done in redis or in-memory so simple that it is easy to see that they are doing the right thing. This should help a lot in them both behaving the same.Other Changes
Notifier
(this is also to ensure that any summary added always has notifications - this simplifies the cleanup)Notifier
API directly in the service causing chaos with the messages where it would start and end twice and discard some of them. This was moved to the job and usingJobProgress
. A cleanup will be done in another PR.Automatic Testing
Added new tests for the
Notifier
API including the added methods. The tests run with bothInMemoryNotifierStore
andRedisNotifierStore
but using aFakeRedis
. TheFakeRedis
itself is also tested directly to make sure it is a proper substitute for the real one.Manual Testing
...